<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>原型与原型链</title>
  </head>
  <body>
    <script>
      /* 
        1. 函数的prototype属性
            - 每个函数都有一个prototype属性，它默认指向一个object空对象（即称原型对象）
            - 原型对象中有一个属性constructor，它指向函数对象
        2. 给原型对象添加属性（一般都是方法）
            作用：函数的所有实例对象自动拥有原型中的属性（方法）
        3. 每个函数function都有一个prototype，即显式原型（属性）
        4. 每个实例对象都有一个__proto__，可称为隐式原型（属性）
        5. 对象的隐式原型的值为其对应构造函数的显式原型的值
        6. 总结：
              - 函数的prototype属性：在定义函数时自动添加的，默认值是一个空的Object对象
              - 对象的__proto__属性：创建对象的时候自动添加的，默认值为构造函数的prototype属性值
              - 程序员能直接操作显式原型，但不能直接操作隐式原型（ES6之前）
        7. 原型链：
              访问一个对象的属性时
              先在自身属性中查找，找到返回
              如果没有，再沿着__proto__这条链向上查找，找到返回
              如果最终没有找到，返回undefined
           别名：隐式原型链
           作用：查找对象的属性或方法
        8. 函数的显式原型指向的是对象默认是空Object实例对象（但Object不满足）
        9. 所有函数都是Function的实例（包括Function）
        10. 读取对象的属性值时：会自动到原型链中查找
            设置对象的属性值时：不会查找原型链，如果当前对象中没有此属性，直接添加此属性并设置其值
            方法一般定义在原型中，属性一般通过构造函数定义在对象本身上
         */

      function Fn() {
        /* 
        内部操作：this.prototype = {}
         */
      }
      var fn = new Fn(); // 内部操作：fn.__proto__ = Fn.prototype
      console.log(Object.prototype.__proto__ === null);
    </script>
  </body>
</html>
